core: Ensure we delete duplicate files in a transaction
authorColin Walters <walters@verbum.org>
Sun, 15 Jan 2012 17:25:52 +0000 (12:25 -0500)
committerColin Walters <walters@verbum.org>
Sun, 15 Jan 2012 17:25:52 +0000 (12:25 -0500)
If multiple files have the same hash, we need to ensure we're not
overwriting other tempfiles in the same transaction.  Instead
just delete them, since we know they're in the repo.

src/libostree/ostree-core.c
src/libostree/ostree-repo.c

index 90cf6ce6fc8b6f00181a599e40d6b0c908ec7573..c2dfd11ceee1df4238da51f77bd173bc471a4c9b 100644 (file)
@@ -887,7 +887,7 @@ ostree_create_temp_file_from_input (GFile            *dir,
       g_free (possible_name);
       possible_name = subst_xxxxxx (tmp_name->str);
       g_clear_object (&possible_file);
-      possible_file = ot_gfile_new_for_path (possible_name);
+      possible_file = g_file_get_child (dir, possible_name);
       
       if (!ostree_create_file_from_input (possible_file, finfo, xattrs, input,
                                           objtype,
index 9def9e56000a169b1caef79142a13a177a2781e7..c0863656ea5bc44ec5f49f5dbe5f025c7f8dbc9d 100644 (file)
@@ -755,6 +755,39 @@ stage_object_impl (OstreeRepo         *self,
                    GCancellable       *cancellable,
                    GError            **error);
 
+static gboolean
+insert_into_transaction (OstreeRepo        *self,
+                         const char        *checksum,
+                         OstreeObjectType   objtype,
+                         GFile             *tempfile_path,
+                         GError           **error)
+{
+  gboolean ret = FALSE;
+  OstreeRepoPrivate *priv = GET_PRIVATE (self);
+  char *key;
+
+  key = create_checksum_and_objtype (checksum, objtype);
+
+  if (g_hash_table_lookup (priv->pending_transaction_tmpfiles, key))
+    {
+      if (unlink (ot_gfile_get_path_cached (tempfile_path)) < 0)
+        {
+          ot_util_set_error_from_errno (error, errno);
+          goto out;
+        }
+      g_free (key);
+    }
+  else
+    {
+      g_hash_table_insert (priv->pending_transaction_tmpfiles,
+                           key, g_strdup (ot_gfile_get_basename_cached (tempfile_path)));
+    }
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
 static gboolean
 impl_stage_archive_file_object_from_raw (OstreeRepo         *self,
                                          GFileInfo          *file_info,
@@ -828,12 +861,13 @@ impl_stage_archive_file_object_from_raw (OstreeRepo         *self,
   else
     actual_checksum = g_checksum_get_string (ret_checksum);
 
-  g_hash_table_insert (priv->pending_transaction_tmpfiles,
-                       create_checksum_and_objtype (actual_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT),
-                       g_strdup (ot_gfile_get_basename_cached (content_temp_file)));
-  g_hash_table_insert (priv->pending_transaction_tmpfiles,
-                       create_checksum_and_objtype (actual_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META),
-                       g_strdup (ot_gfile_get_basename_cached (meta_temp_file)));
+  if (!insert_into_transaction (self, actual_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT,
+                                content_temp_file, error))
+    goto out;
+
+  if (!insert_into_transaction (self, actual_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
+                                meta_temp_file, error))
+    goto out;
 
   ret = TRUE;
   ot_transfer_out_value (out_checksum, &ret_checksum);
@@ -910,7 +944,7 @@ stage_object_impl (OstreeRepo         *self,
       else 
         {
           if (!ostree_create_temp_file_from_input (priv->transaction_dir,
-                                                   "store-tmp-", NULL,
+                                                   ostree_object_type_to_string (objtype), NULL,
                                                    file_info, xattrs, input,
                                                    objtype,
                                                    &temp_file,
@@ -933,9 +967,9 @@ stage_object_impl (OstreeRepo         *self,
                 }
             }
           
-          g_hash_table_insert (priv->pending_transaction_tmpfiles,
-                               create_checksum_and_objtype (actual_checksum, objtype),
-                               g_strdup (ot_gfile_get_basename_cached (temp_file)));
+          if (!insert_into_transaction (self, actual_checksum, objtype, 
+                                        temp_file, error))
+            goto out;
           g_clear_object (&temp_file);
         }
     }